/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @brief NFC设备管理模块API实现
 * @file device_manager.c
 */

#include "nci_api.h"
#include "nci_core.h"
#include "nci_module.h"
#include "nfc_log_api.h"
#include "nfa_dm.h"
#include "nci_feature.h"
#include "message_queue.h"
#include "nci_transport.h"
#include "nfc_transport_api.h"
#include "nfc_config_api.h"
#include "nfc_hex_utils.h"
#include "nci_task.h"
#ifdef OSI_ALLOCATOR_DEBUG
#include "nfc_debug_api.h"
#endif

#define NCI_REG_NFCC_CONFIG_CONTROL 0x85

typedef enum {
    NCI_DM_STATE_DISABLED = 0,
    NCI_DM_STATE_ENABLEING,
    NCI_DM_STATE_ENABLED,
    NCI_DM_STATE_DISABLEING,
    NCI_DN_STATE_MAX,
} tNCI_DM_STATE;

const char* s_nci_dm_state_names[] = {
    "DISABLED", "ENABLEING", "ENABLED", "DISABLEING", "UNKNOWN",
};
const char* s_nci_module_state_names[] = {
    "DISABLED", "ENABLED", "REMOVED", "UNKNOWN",
};

bool g_dta_mode_enabled = false;

extern tNCI_MODULE g_power_manager;
extern tNCI_MODULE g_data_manager;
extern tNCI_MODULE g_discover_manager;
extern tNCI_MODULE g_routing_manager;
#if IS_FEATURE_ON(NCI_FEATURE_EE)
extern tNCI_MODULE g_nfcee_manager;
#endif // IS_FEATURE_ON(NCI_FEATURE_EE)
#if IS_FEATURE_ON(NCI_FEATURE_RW)
extern tNCI_MODULE g_rw_manager;
#endif // IS_FEATURE_ON(NCI_FEATURE_RW)
#if IS_FEATURE_ON(NCI_FEATURE_CE)
extern tNCI_MODULE g_ce_manager;
#endif // IS_FEATURE_ON(NCI_FEATURE_CE)
#if IS_FEATURE_ON(NCI_FEATURE_HCI)
extern tNCI_MODULE g_hci_manager;
#endif // IS_FEATURE_ON(NCI_FEATURE_HCI)
#if IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
extern tNCI_MODULE g_wiredse_manager;
#endif // IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
#if IS_FEATURE_ON(NCI_FEATURE_VS)
extern tNCI_MODULE g_vs_manager;
#endif /* IS_FEATURE_ON(NCI_FEATURE_VS) */

static tNCI_MODULE* s_all_module[] = {
    &g_power_manager,
    &g_data_manager,
    &g_discover_manager,
#if IS_FEATURE_ON(NCI_FEATURE_EE)
    &g_nfcee_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_EE)
#if IS_FEATURE_ON(NCI_FEATURE_HCI)
    &g_hci_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_HCI)
#if IS_FEATURE_ON(NCI_FEATURE_ROUTING)
    &g_routing_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_ROUTING)
#if IS_FEATURE_ON(NCI_FEATURE_RW)
    &g_rw_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_RW)
#if IS_FEATURE_ON(NCI_FEATURE_CE)
    &g_ce_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_CE)
#if IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
    &g_wiredse_manager,
#endif // IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
#if IS_FEATURE_ON(NCI_FEATURE_VS)
    &g_vs_manager,
#endif /* IS_FEATURE_ON(NCI_FEATURE_VS) */
};

static size_t s_module_count = sizeof(s_all_module) / sizeof(tNCI_MODULE*);

static tATOMIC s_state = NCI_DM_STATE_DISABLED;

static tNCI_CORE_RESET_NTF s_core_reset_ntf;

/**
 * @brief 关闭所有NCI模块
 */
static tNCI_STATUS disable_all_module(bool is_shutdown) {
    for (int i = s_module_count - 1; i >= 0; i--) {
        tNCI_MODULE *module = s_all_module[i];
        if (module && module->state == NCI_MODULE_STATE_ENABLED) {
            tNCI_STATUS ret = module->deinit(is_shutdown);
            module->state = NCI_MODULE_STATE_DISABLED;
            NFCLOG_I("module %s deinit, ret = %d", module->name, ret);
        }
    }
    NFCLOG_I("disable all module success");
    return NCI_STATUS_OK;
}

/**
 * @brief 打开所有NCI模块
 */
static tNCI_STATUS enable_all_module(const tNCI_MODULE_INIT_CFG *p_cfg) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    for (int i = 0; i < s_module_count; ++i) {
        tNCI_MODULE *module = s_all_module[i];
        if (module && module->state == NCI_MODULE_STATE_DISABLED) {
            ret = module->init(p_cfg);
            if (ret == NCI_STATUS_OK) {
                module->state = NCI_MODULE_STATE_ENABLED;
            } else {
                NFCLOG_E("module %s init failed, ret = %d", module->name, ret);
                return ret;
            }
        }
    }
    NFCLOG_I("enable all module success");
    return NCI_STATUS_OK;
}

static tNCI_STATUS set_init_config() {
    if (g_dta_mode_enabled) {
        NFCLOG_I("DTA mode enabled, skip set nfcc config control");
        return NCI_STATUS_OK;
    }
    uint8_t nfcc_config_control = 0x01;
    tNCI_REG reg = {
        .id = NCI_REG_NFCC_CONFIG_CONTROL,
        .len = 1,
        .value = &nfcc_config_control,
    };
    tNCI_STATUS ret = nci_core_set_config(&reg, 1);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("set NFCC config control failed, ret = %d", ret);
        goto exit;
    }
exit:
    return ret;
}

/**
 * @brief 打开NCI协议栈
 */
tNCI_STATUS nfa_enable(const tNCI_INIT_CFG *p_cfg) {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    // 检查当前DM状态是否是关闭状态
    tNCI_DM_STATE dm_state = osi_atomic_read(&s_state);
    if (dm_state != NCI_DM_STATE_DISABLED) {
        NFCLOG_E("nci is already enabled or in enableing process, state = %d", dm_state);
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    // 读取当前DM状态并写入为开启中状态
    dm_state = osi_atomic_read_then_write(&s_state, NCI_DM_STATE_ENABLEING);
    if (dm_state != NCI_DM_STATE_DISABLED) {
        // 写入前的状态不是关闭状态，说明有其他线程已经抢先执行了，返回错误
        NFCLOG_E("may be other threads that have preempted execution and do not repeat execution , state before writing = %d", dm_state);
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }

    // 0. Initialize log
    g_dta_mode_enabled = p_cfg->enable_dta_mode;
    nfc_config_reset();
    const tNFC_CF *cf = nfc_config_get();
    NFCLOG_I("set log level=%d, dta_mode=%d", cf->nci_log_level, g_dta_mode_enabled);
    nfc_log_set_level(cf->nci_log_level);

    // 1. Initialize NCI
    ret = nci_init();
    if (ret != NCI_STATUS_OK) {
        goto exit;
    }

    // 2. Reset NFCC
    osi_memset_s(&s_core_reset_ntf, sizeof(tNCI_CORE_RESET_NTF), 0, sizeof(tNCI_CORE_RESET_NTF));
    tNCI_RESET_TYPE reset_type = KEEP_CONFIG;
    if (tp_is_config_modified() == NFC_STATUS_OK) {
        reset_type = RESET_CONFIG;
        NFCLOG_I("config is modified, need reset config");
    }
    ret = nci_core_reset(reset_type, &s_core_reset_ntf);
    if (ret != NCI_STATUS_OK) {
        goto failed_deinit_nci;
    }

    // 3. Initialize NFCC
    tNCI_MODULE_INIT_CFG init_cfg = {0};
    ret = nci_core_init(&init_cfg.init_resp);
    if (ret != NCI_STATUS_OK) {
        goto failed_deinit_nci;
    }

    // 4. hal core init
    ret = nci_tp_core_initialized();
    if (ret != NCI_STATUS_OK) {
        goto failed_deinit_nci;
    }

    // 5. init all module
    init_cfg.p_external_cfg = p_cfg;
    ret = enable_all_module((const tNCI_MODULE_INIT_CFG*) (&init_cfg));
    if (ret != NCI_STATUS_OK) {
        goto failed_disable_modules;
    }

    // 6. set init config
    ret = set_init_config();
    if (ret != NCI_STATUS_OK) {
        goto failed_disable_modules;
    }

    osi_atomic_write(&s_state, NCI_DM_STATE_ENABLED);
    NFCLOG_I("nci enable success");
    return NCI_STATUS_OK;
failed_disable_modules:
    disable_all_module(false);
failed_deinit_nci:
    nci_deinit(false);
    osi_atomic_write(&s_state, NCI_DM_STATE_DISABLED);
exit:
#ifdef OSI_ALLOCATOR_DEBUG
    osi_memory_dump();
#endif
    return ret;
}

/**
 * @brief 关闭NCI协议栈
 *
 * @param is_shutdown 是否进入关机模式，true为关机模式，false为正常关闭
 *
 * @note 关机模式不会向NFCC设置RF状态和NFCEE状态，但会关闭所有模块
 *
 * @return NCI_STATUS_OK 关闭成功，其他值表示关闭失败
 */
tNCI_STATUS nfa_disable(bool is_shutdown) {
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    // 检查当前DM状态是否是开启状态
    tNCI_DM_STATE dm_state = osi_atomic_read(&s_state);
    if (dm_state != NCI_DM_STATE_ENABLED) {
        NFCLOG_E("nci is already disabled or in disableing process, state = %d", dm_state);
        ret = NCI_STATUS_EXT_STATE_INCORRECT;
        goto exit;
    }
    // 读取当前DM状态并写入为关闭中状态
    dm_state = osi_atomic_read_then_write(&s_state, NCI_DM_STATE_DISABLEING);
    if (dm_state != NCI_DM_STATE_ENABLED) {
        // 写入前的状态不是开启状态，说明有其他线程已经抢先执行了，返回错误
        NFCLOG_E("may be other threads that have preempted execution and do not repeat execution , state before writing = %d", dm_state);
        ret = NCI_STATUS_EXT_STATE_INCORRECT;
        goto exit;
    }
    // 1. deinit discover manager
    if (g_discover_manager.state == NCI_MODULE_STATE_ENABLED) {
        ret = g_discover_manager.deinit(is_shutdown);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_W("deinit discover manager failed, ret = %d", ret);
        }
        g_discover_manager.state = NCI_MODULE_STATE_DISABLED;
    }

    ret = disable_all_module(is_shutdown);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("disable all module failed, ret=%d", ret);
    }

    ret = nci_deinit(is_shutdown);
    NFCLOG_I("nci_deinit is_shutdown=%d, ret=%d", is_shutdown, ret);
    osi_atomic_write(&s_state, NCI_DM_STATE_DISABLED);
exit:
    nfc_config_reset();
#ifdef OSI_ALLOCATOR_DEBUG
    osi_memory_dump();
#endif
    return ret;
}

/**
 * @brief DUMP NCI状态
 *
 * @param fd 保存DUMP信息的文件描述符
 */
void nfa_dump(int fd) {
    uint8_t state_index = (uint8_t) osi_atomic_read(&s_state);
    if (state_index > NCI_DN_STATE_MAX) {
        state_index = NCI_DN_STATE_MAX;
    }
    osi_dump(fd, "============NCI DUMP START============");
    osi_dump(fd, "DM State: %s", s_nci_dm_state_names[state_index]);
    osi_dump(fd, "NCI_VERSION: 0x%02X", nfa_get_nci_version());
    osi_dump(fd, "NCI_FEATURE: 0x%08X", nfa_get_nci_feature());
    osi_dump(fd, "SW_VERSION: %d", nfa_get_sw_version());
    const uint8_t dump_buf_len = 30;
    char *dump_buf = osi_calloc(dump_buf_len);
    if (dump_buf) {
        tNCI_STATUS ret = nfa_get_build_time(dump_buf, dump_buf_len);
        if (ret == NCI_STATUS_OK) {
            osi_dump(fd, "BUILD_TIME: %s", dump_buf);
        }
        osi_memset_s(dump_buf, dump_buf_len, 0, dump_buf_len);
        bytes_to_hex((uint8_t*) &s_core_reset_ntf, sizeof(tNCI_CORE_RESET_NTF), dump_buf);
        osi_dump(fd, "CORE_RESET_NTF: %s", dump_buf);
        osi_free(dump_buf);
    }


    osi_dump(fd, "");
    for (int i = 0; i < s_module_count; i++) {
        tNCI_MODULE *p_module = s_all_module[i];
        uint8_t module_state_index = (uint8_t)p_module->state;
        if (module_state_index > NCI_MODULE_STATE_MAX) {
            module_state_index = NCI_MODULE_STATE_MAX;
        }
        osi_dump(fd, "Module(%s) START:", p_module->name);
        osi_dump(fd, "Module State: %s", s_nci_module_state_names[module_state_index]);
        if (p_module->dump) {
            p_module->dump(fd);
        }
        osi_dump(fd, "Module(%s) END.", p_module->name);
        osi_dump(fd, "");
    }
    osi_dump(fd, "============NCI DUMP END==============");
}
/**
 * @brief 检查NFCC固件升级
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_check_firmware() {
    if (osi_atomic_read(&s_state) != NCI_DM_STATE_DISABLED) {
        NFCLOG_E("nci must be disabled before check firmware");
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    tNFC_STATUS ret = tp_check_firmware();
    if (ret != NFC_STATUS_OK) {
        NFCLOG_E("check firmware failed, ret=%d", ret);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}
/**
 * @brief 执行恢复出厂设置
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_factory_reset() {
    if (osi_atomic_read(&s_state) != NCI_DM_STATE_DISABLED) {
        NFCLOG_E("nci must be disabled before factory reset");
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    tNFC_STATUS ret = tp_factory_reset();
    if (ret != NFC_STATUS_OK) {
        NFCLOG_E("factory reset failed, ret=%d", ret);
        return NCI_STATUS_EXT_FAILED;
    }
    return NCI_STATUS_OK;
}
/**
 * @brief 获取NCI版本号
 *
 * @return 返回NCI版本号
 */
tNCI_VERSION nfa_get_nci_version() {
    return NCI_VERSION_2_0;
}
/**
 * @brief 获取MW软件版本号
 *
 * @return 返回软件版本号
 */
uint32_t nfa_get_sw_version() {
    uint32_t version_code = 100; // 1.0.0
    uint32_t publish_time = 240902; // 2024.09.02
    return (version_code * 1000000) + publish_time; // 1.0.0 2024.09.02;
}

/**
 * @brief 获取协议栈编译时间
 *
 * @param[out] build_time 保存编译时间的字符串
 * @param[in] len 保存编译时间的字符串长度，必须大于等于12
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_get_build_time(char *build_time, uint8_t len) {
    const uint8_t date_str_len = 11;
    const uint8_t time_str_len = 8;
    const char *date = "" __DATE__; // "Sep 24 2019"
    const char *time = "" __TIME__; // "14:47:05"
    if (strlen(date) < date_str_len || strlen(time) < time_str_len) {
        NFCLOG_E("get build time failed");
        return NCI_STATUS_EXT_FAILED;
    }
    const uint8_t min_build_time_str_len = 12; // 241001.9030 + \0
    if (!build_time || len < min_build_time_str_len) {
        NFCLOG_E("invalid build time or len=%d", len);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    const uint8_t month_count = 12;
    const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    uint8_t year = 0, month = 0, day = 0, hour = 0, min = 0;
    for (uint8_t i = 0; i < month_count; i++) {
        if (memcmp(date, months[i], 3) == 0) {
            month = i + 1;
        }
    }

    if (month == 0) {
        NFCLOG_E("invalid month: %s", date);
        return NCI_STATUS_EXT_FAILED;
    }

    day = (uint8_t) atoi(date + 4);
    year = (uint8_t) atoi(date + 9); // 只取年份的后两位
    hour = (uint8_t) atoi(time);
    min = (uint8_t) atoi(time + 3);

    int count = 0;
    return osi_snprintf_s(build_time, len, &count, "%02d%02d%02d.%02d%02d", year, month, day, hour, min) ? NCI_STATUS_OK : NCI_STATUS_EXT_FAILED;
}
/**
 * @brief 获取当前开启的NCI_FEATURE
 * @return 返回当前开启的NCI_FEATURE
 */
uint32_t nfa_get_nci_feature() {
    return NCI_FEATURE;
}
/**
 * @brief 获取NFCC厂商信息
 *
 * @param[out] p_rsp 返回的厂商信息
 * @note 当返回状态为NCI_STATUS_OK时，p_rsp有效
 * @note p_rsp需要调用nfa_utils_free_rsp释放
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_get_manuf_spec_info(tNCI_RSP *p_rsp) {
    if (!p_rsp) {
        NFCLOG_E("p_rsp is null");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (NCI_DM_STATE_ENABLED != osi_atomic_read(&s_state)) {
        NFCLOG_E("nci must be enabled before get manuf spec info");
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }
    uint8_t length = s_core_reset_ntf.manufacturer_specific_infomation_length;
    if (length == 0) {
        NFCLOG_E("manufacturer specific information is empty");
        return NCI_STATUS_EXT_FAILED;
    }
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    p_rsp->data = osi_calloc(length);
    if (!p_rsp->data) {
        NFCLOG_E("alloc failed");
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }
    if (!osi_memcpy_s(p_rsp->data, length, s_core_reset_ntf.manufacturer_specific_infomation, length)) {
        NFCLOG_E("copy manufacturer specific information failed");
        ret = NCI_STATUS_EXT_COPY_FAILED;
        goto cleanup;
    }
    p_rsp->len = length;
    return NCI_STATUS_OK;

cleanup:
    osi_free(p_rsp->data);
    p_rsp->len = 0;
    return ret;
}

/**
 * @brief 设置DTA模式开关
 * @param enable true为开启DTA模式，false为关闭DTA模式
 */
void nfa_dm_set_dta_mode(bool enable) {
    g_dta_mode_enabled = enable;
    NFCLOG_I("dta mode %s", enable ? "enabled" : "disabled");
}

/**
 * @brief 注入NTF消息并让协议栈处理
 *
 * @param p_ntf NTF消息数据，完整NCI指令：[HDR0][HDR1][LEN][DATA]
 * @param ntf_len NTF消息数据长度，即p_ntf的长度
 * @param delay_ms 设置延迟发送时间，单位ms，立即发送设置为0
 *
 * @return 写入成功返回NCI_STATUS_OK，否则返回错误码
 */
tNCI_STATUS nfa_dm_inject_ntf(uint8_t *p_ntf, uint16_t ntf_len, uint32_t delay_ms) {
    OSI_CHK_PARAM_INVALID(!p_ntf, return NCI_STATUS_INVALID_PARAM);
    OSI_CHK_PARAM_INVALID(ntf_len == 0, return NCI_STATUS_INVALID_PARAM);
    if (osi_atomic_read(&s_state) != NCI_DM_STATE_ENABLED) {
        NFCLOG_E("nci must be enabled before inject ntf");
        return NCI_STATUS_EXT_STATE_INCORRECT;
    }

    uint8_t hdr0 = p_ntf[0];
    if ((hdr0 & 0xF0) != 0x60) {
        // 只允许NTF类型的数据，并且不支持PBF
        NFCLOG_E("invalid ntf header: 0x%02X", hdr0);
        return NCI_STATUS_EXT_INVALID_PARAM;
    }

    // 因为要交由消息队列处理，所以需要复制一份数据
    uint8_t *p_data = osi_calloc(ntf_len);
    if (!p_data) {
        NFCLOG_E("alloc failed");
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }
    if (!osi_memcpy_s(p_data, ntf_len, p_ntf, ntf_len)) {
        NFCLOG_E("copy ntf failed");
        osi_free(p_data);
        return NCI_STATUS_EXT_COPY_FAILED;
    }
    tNCI_STATUS ret = nci_task_post_delay(NCI_TASK_EVT_TRANSPORT_INJECT_NTF, ntf_len, 0, p_data, delay_ms);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("post inject ntf failed, ret=%d", ret);
        osi_free(p_data);
        return ret;
    }
    // 消息发送成功后p_data会在消息队列中释放，不需要在这里释放
    return NCI_STATUS_OK;
}
